package org.example;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.ptr.IntByReference;
import org.example.library.WintunExtensionLibrary;
import org.example.library.WintunLibrary;
import org.pcap4j.packet.*;

import java.util.Optional;

public class ClientMain {

    public static void main(String[] args){

        String name = "Test";
        String tunnelType = "Wintun";
        //创建网络适配器
        Pointer adapterHandle = WintunLibrary.INSTANCE.WintunCreateAdapter(new WString(name), new WString(tunnelType), null);

        if (adapterHandle == null) {
            throw new RuntimeException("网络适配器创建失败！(可能是没用管理员启动)");
        }

        String host = Optional.ofNullable(System.getenv("host")).orElse("localhost");
        int port = Integer.parseInt(Optional.ofNullable(System.getenv("port")).orElse("9999"));

        var connectServer = new ConnectServer(host,port);

        if(!connectServer.clientChannel.isOpen()){
            throw new RuntimeException(String.format("连接服务器异常，%s:%d。",
                    connectServer.host,connectServer.port));
        }

        var hostAddress = connectServer.address.getHostAddress();
        //设置网络设配器ip 和 子网掩码
        WintunExtensionLibrary.INSTANCE.CreateAddressRow(adapterHandle,hostAddress,24);

        //启动适配器
        Pointer sessionHandle = WintunLibrary.INSTANCE.WintunStartSession(adapterHandle, 0x400000);

        connectServer.pointer = sessionHandle;

        while (true){

            //读取适配器数据包
            IntByReference incomingPacketSize = new IntByReference();
            Pointer incomingPacket = WintunLibrary.INSTANCE.WintunReceivePacket(sessionHandle, incomingPacketSize);

            if (incomingPacket != null) {
                try {
                    int packetSize = incomingPacketSize.getValue();
                    byte[] packetBytes = incomingPacket.getByteArray(0, packetSize);

                    //解析数据包
                    IpPacket packet = (IpPacket) IpSelector.newPacket(packetBytes, 0, packetBytes.length);
                    System.out.println(packet);

                    if(packet.getPayload() instanceof TcpPacket || packet.getPayload() instanceof UdpPacket){
                        connectServer.uploadData(packet.getRawData());
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    WintunLibrary.INSTANCE.WintunReleaseReceivePacket(sessionHandle, incomingPacket);
                }


            } else {

                int lastError = Native.getLastError();
                if (lastError == 0x103) {
                    //没数据等待数据
                    Pointer readWaitEvent = WintunLibrary.INSTANCE.WintunGetReadWaitEvent(sessionHandle);
                } else {
                    WintunLibrary.INSTANCE.WintunCloseAdapter(sessionHandle);
                    throw new RuntimeException("数据包读取失败，错误码："+lastError);
                }
            }

        }
    }

}